# SQLAppender.java

    package org.codefilarete.stalactite.query.builder;

    import javax.annotation.Nullable;

    import org.codefilarete.stalactite.query.model.Fromable;
    import org.codefilarete.stalactite.query.model.Selectable;

    /**
     * The contract for printing a where clause : need to print a String and a value.
     * Then you can print a prepared statement or a valued statement.
     */
    public interface SQLAppender {

    	/**
    	 * Appends a {@link String} to the underlying result. Used for keywords, column name, etc
    	 *
    	 * @param s a basic {@link String}
    	 * @return this
    	 */
    	SQLAppender cat(String s, String... ss);

    	/**
    	 * Called when a value must be "printed" to the underlying result. Implementations will differ on this point depending on the target goal:
    	 * values printed in the SQL statement (bad practice because of SQL injection) or prepared statement
    	 *
    	 * @param column context of the value to be printed
    	 * @param value the object to be added/printed to the statement
    	 * @return this
    	 * @param <V> value type
    	 */
    	<V> SQLAppender catValue(@Nullable Selectable<V> column, Object value);

    	/**
    	 * Appends value to the underlying statement. To be used when {@link #catValue(Selectable, Object)} can't be applied.
    	 *
    	 * @param value the value to be printed
    	 * @return this
    	 */
    	SQLAppender catValue(Object value);

    	/**
    	 * Appends column name to underlying SQL statement.
    	 *
    	 * @param column the column to be printed
    	 * @return this
    	 */
    	SQLAppender catColumn(Selectable<?> column);

    	SQLAppender catTable(Fromable table);

    	SQLAppender removeLastChars(int length);

    	default SQLAppender catIf(boolean condition, String s) {
    		if (condition) {
    			cat(s);
    		}
    		return this;
    	}

    	default boolean isEmpty() {
    		return getSQL().isEmpty();
    	}

    	String getSQL();

    	SubSQLAppender newSubPart(DMLNameProvider dmlNameProvider);

    	interface SubSQLAppender extends SQLAppender {

    		SubSQLAppender cat(String s, String... ss);

    		<V> SubSQLAppender catValue(@Nullable Selectable<V> column, Object value);

    		SubSQLAppender catValue(Object value);

    		SubSQLAppender catColumn(Selectable<?> column);

    		SubSQLAppender catTable(Fromable table);

    		SubSQLAppender removeLastChars(int length);

    		SQLAppender close();
    	}

    	abstract class DefaultSubSQLAppender implements SubSQLAppender {

    		private final SQLAppender delegate;

    		public DefaultSubSQLAppender(SQLAppender delegate) {
    			this.delegate = delegate;
    		}

    		public SQLAppender getDelegate() {
    			return delegate;
    		}

    		@Override
    		public SubSQLAppender cat(String s, String... ss) {
    			delegate.cat(s, ss);
    			return this;
    		}

    		@Override
    		public <V> SubSQLAppender catValue(@Nullable Selectable<V> column, Object value) {
    			delegate.catValue(column, value);
    			return this;
    		}

    		@Override
    		public SubSQLAppender catValue(Object value) {
    			delegate.catValue(value);
    			return this;
    		}

    		@Override
    		public SubSQLAppender catColumn(Selectable<?> column) {
    			delegate.catColumn(column);
    			return this;
    		}

    		@Override
    		public SubSQLAppender catTable(Fromable table) {
    			delegate.catTable(table);
    			return this;
    		}

    		@Override
    		public SubSQLAppender removeLastChars(int length) {
    			delegate.removeLastChars(length);
    			return this;
    		}

    		@Override
    		public SubSQLAppender catIf(boolean condition, String s) {
    			delegate.catIf(condition, s);
    			return this;
    		}

    		@Override
    		public boolean isEmpty() {
    			return delegate.isEmpty();
    		}

    		@Override
    		public String getSQL() {
    			return delegate.getSQL();
    		}

    		@Override
    		public SubSQLAppender newSubPart(DMLNameProvider dmlNameProvider) {
    			return delegate.newSubPart(dmlNameProvider);
    		}
    	}
    }